import * as ExcelJS from 'exceljs';
import { saveAs } from 'file-saver';
import _ from 'lodash';

// 52个不够用再加
export const AZ = [
  'A',
  'B',
  'C',
  'D',
  'E',
  'F',
  'G',
  'H',
  'I',
  'J',
  'K',
  'L',
  'M',
  'N',
  'O',
  'P',
  'Q',
  'R',
  'S',
  'T',
  'U',
  'V',
  'W',
  'X',
  'Y',
  'Z',
  'AA',
  'BB',
  'CC',
  'DD',
  'EE',
  'FF',
  'GG',
  'HH',
  'II',
  'JJ',
  'KK',
  'LL',
  'MM',
  'NN',
  'OO',
  'PP',
  'QQ',
  'RR',
  'SS',
  'TT',
  'UU',
  'VV',
  'WW',
  'XX',
  'YY',
  'ZZ',
];

const getColumns = ({ columns, data }) => {
  let deepLv = 1; // 表头有几行
  let myColumns = []; // 导出表头格式
  const _getWidth = (arr) => {
    // 列宽自适应
    const lens = arr.map((v) => {
      if (!v) return 10;
      if (v.toString().charCodeAt(0) > 255) {
        return v.toString().length * 2;
      }
      return v.toString().length;
    });
    return _.max(lens);
  };

  // 递归取叶子节点，填表头名称，获取表头最大行数
  const _fn = (list = [], headers = [], lv = 1) => {
    if (lv > deepLv) deepLv = lv;
    for (let i = 0; i < list.length; i++) {
      const item = list[i];
      const headNames = [...headers, item.name];
      if (!!item.children?.length) {
        _fn(item.children, headNames, lv + 1);
      } else {
        myColumns.push({
          header: headNames,
          key: item.code,
          width: _getWidth([...data.map((x) => x[item.code]), ...headNames]),
          style: {
            alignment: {
              vertical: 'middle',
              horizontal: item.align || 'center',
            },
          },
        });
      }
    }
  };
  _fn(columns, [], 1);
  return {
    myColumns,
    deepLv,
  };
};

const getMerHead = ({ columns, deepLv }) => {
  // 计算表头单元格合并
  let result = [];
  columns.map(({ header }, i) => {
    const rowLen = header.length;
    if (rowLen < deepLv) {
      result.push(`${AZ[i]}${rowLen}:${AZ[i]}${deepLv}`);
    }
  });
  for (let j = 0; j < deepLv; j++) {
    for (let i = 0; i < columns.length; i++) {
      const { header } = columns[i];
      const name = header[j];
      if (name && i < columns.length - 1) {
        let count = 0;
        while (columns[i + count + 1]?.header?.[j] === name) {
          count++;
        }
        if (count > 0) {
          result.push(`${AZ[i]}${j + 1}:${AZ[i + count]}${j + 1}`);
          i = i + count;
        }
      }
    }
  }
  return result;
};

const getMerBody = ({ data, columns, merges, deepLv }) => {
  // 计算数据单元格合并
  let result = [];
  let _colMap = {}; // key = 值_起始行_结束行

  // 单列合并查找
  merges.map((k) => {
    const colI = columns.findIndex((x) => x.key === k); // 列索引
    const values = data.map((x) => x[k]);
    for (let i = 0; i < values.length; i++) {
      let count = 0;
      const value = values[i];
      while (values[i + count + 1] === value) {
        count++;
      }
      if (count > 0) {
        const startRow = i + deepLv + 1;
        const endRow = startRow + count;
        const uniqKey = [value, startRow, endRow].join('_____');
        if (!_colMap[uniqKey]) _colMap[uniqKey] = [];
        _colMap[uniqKey].push(colI);
        i += count;
      }
    }
  });
  // 多行多列合并聚合
  for (const key in _colMap) {
    const [value, startRow, endRow] = key.split('_____');
    const list = _colMap[key];
    if (list.length > 1) {
      const mutiColStart = _.min(list);
      const mutiColEnd = _.max(list);
      result.push(`${AZ[mutiColStart]}${startRow}:${AZ[mutiColEnd]}${endRow}`);
    } else {
      const colI = list[0];
      result.push(`${AZ[colI]}${startRow}:${AZ[colI]}${endRow}`);
    }
  }
  // 单行合并查找
  data.map((row, i) => {
    for (let j = 0; j < merges.length; j++) {
      let count = 1;
      const key = merges[j];
      const value = row[key];
      const colIdx = columns.findIndex((x) => x.key === key);
      // 值相等，切临近
      while (
        data?.[i + 1]?.[key] !== value &&
        data?.[i - 1]?.[key] !== value &&
        row?.[merges?.[j + count]] === value &&
        columns?.[colIdx + count]?.key === merges[j + count]
      ) {
        count++;
      }
      if (count > 1) {
        const rowI = i + deepLv + 1;
        result.push(`${AZ[colIdx]}${rowI}:${AZ[colIdx + count - 1]}${rowI}`);
        j += count - 1;
      }
    }
  });
  return result;
};

export default ({ columns = [], data = [], filename = '导出', merges = [] }) => {
  // 计算表头合并
  const { myColumns, deepLv } = getColumns({ columns, data });
  const merHead = getMerHead({
    columns: myColumns,
    deepLv,
  });
  const merBody = getMerBody({
    data,
    columns: myColumns,
    merges,
    deepLv,
  });
  const myMerges = [...merHead, ...merBody];

  // 创建工作薄
  let workbook = new ExcelJS.Workbook();
  let worksheet = workbook.addWorksheet(filename);
  worksheet.columns = myColumns;
  // 数据
  data.map((x) => worksheet.addRow(x));
  // 合并行列
  myMerges.map((x) => worksheet.mergeCells(x));
  // 下载
  workbook.xlsx.writeBuffer().then((buffer) => {
    saveAs(new Blob([buffer], { type: 'application/octet-stream' }), `${filename}.xlsx`);
  });
};
